﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

//调整数组使奇数全部都位于偶数前面。

//void change_number(int arr1[], int sz1)
//{
//	int left = 0;
//	int right = sz1 - 1;
//	int tmp = 0;
//	while (left < right)
//	{
//		//寻找奇数
//		while ((left < right) && (arr1[left] % 2 == 1))
//		{
//			left++;
//		}
//		//寻找偶数
//		while ((left < right) && (arr1[right] % 2 == 0))
//		{
//			right--;
//		}
//		//交换两数
//		if (left < right)
//		{
//			tmp = arr1[left];
//			arr1[left] = arr1[right];
//			arr1[right] = tmp;
//		}
//	}
//}
//int main()
//{
//	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	printf("交换前：");
//	for (int i = 0; i < sz; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	printf("\n");
//	change_number(arr, sz);
//	printf("交换后：");
//	for (int j = 0; j < sz; j++)
//	{
//		printf("%d ", arr[j]);
//	}
//	return 0;
//}


//10.数组名字的理解
//
//我们知道arr[0]是数组的首元素，&arr[0]是取出数组首元素的地址
//但是平时我们使用数组时也会发现arr本身就是数组首元素地址
//
//代码测试
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("&arr[0]=%p\n", &arr[0]);
	printf("        %p", arr);
	return 0;
}

//我们可以发现数组名就是数组首元素的地址


//如果数组名是首元素地址，下面个代码如何解释呢？
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", sizeof(arr));
	return 0;
}

//由结果我们可以看到是40，但是首元素不是地址吗，应该是4/8个字节才对啊
//其实在C语言中，有两种情况下数字名代表的是整个数组
//
//1.sizeof(数组名) - sizeof单独存放数组名，表示整个数组，计算的是
//整个数组的大小
//
//2.&数组名 - 这里的数组名也表示整个数组，取出的是整个数组的地址
//
//除去以上两种情况，其他任何地方使用数组名都表示首元素地址
//
//
//那么&数组名的具体情况到底是什么呢，让我们来看下面的代码：
//
//代码1

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("&arr[0] = %p\n", &arr[0]);
	printf("arr = %p\n", arr);
	printf("&arr = %p\n", &arr);
	return 0;
}

//看上去好像没有什么变换啊，先别急来看代码2
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("&arr[0] = %p\n", &arr[0]);
	printf("&arr[0]+1 = %p\n", &arr[0] + 1);
	printf("arr = %p\n", arr);
	printf("arr+1 = %p\n", arr + 1);
	printf("&arr = %p\n", &arr);
	printf("&arr+1 = %p\n", &arr + 1);
	return 0;
}

//这里我们就可以知晓答案了，&arr[0]和arr在进行运算的时候只移动了4
//个字节，而&arr在进行运算却是跨过了一个数组的地址



//11.使用指针访问数组
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	for (int i = 0 ; i < sz; i++)
	{
		// printf("%d " ,*(p + i));
		//printf("%d ", p[i]);
	}
	return 0;
}

//无论是第一种输出还是第二种输出，本质是一样的，那就是p指向的是arr
//首元素的地址，可以通过这个访问数组
// p[i] 等价于 *(p+i)



//12.一维数组传参的本质
// 
//我们学过函数了，那么我们可以通过传参来使函数计算我们数组的个数吗？

//代码展示：

void sz_juan(int arr[])
{
	int sz2 = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", sz2);
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz1 = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", sz1);
	sz_juan(arr);
	return 0;
}

//我们可以看见计算的结果并不一样，也就是说本质上数组传参本质上传递的是
//数组首元素的地址

//所以函数形参的部分理论上应该使⽤指针变量来接收⾸元素的地址。那么在函数内部我们写
//sizeof(arr) 计算的是⼀个地址的⼤⼩（单位字节）⽽不是数组的⼤⼩（单位字节）。正是因为函
//数的参数部分是本质是指针，所以在函数内部是没办法求的数组元素个数的。



//13.冒泡排序 - bubble_sort
//核心思想：两两比较

//代码展示：

冒泡排序
void bubble_sort(int arr[], int sz)
{
	int i = 0;
	//优化：
	//int flag = 1;
	for (i = 0; i < sz - 1; i++) // 循环sz-1次
	{
		int j = 0;
		for (j = 0; j < sz - 1 - i; j++)//交换sz-1-i次
		{
			if (arr[j] > arr[j + 1])
			{
				//flag = 0;
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
		//if (flag == 1)
			//break;
	}
}

//打印
void pint(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}

int main()
{
	int arr[10] = { 1,5,9,7,6,4,2,3,8,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz);//排序
	pint(arr, sz);//打印
	return 0;
}


//14.二级指针
//
//我们都知道指针：是指向一个地址的，那么为了存储这个地址我们需要创造
//指针变量用来存储这个地址
//
//那么指针变量的创建也存在地址，这时候二级指针就是用来存放一级指针
//变量地址的指针

//代码展示：
int main()
{
	int a = 10;
	int* p = &a;
	int** pp = &p;
	return 0;
}

//二级指针的运算和一级指针差不多

//如解引用
//*p == a;
//*pp == &a/p;  **pp =a;

int main()
{
	int a = 10;
	int* p = &a;
	int** pp = &p;
	**pp = 30;
	printf("%d ", a);
	return 0;
}


//15.指针数组
//
//在了解指针数组前，我们曾了解字符数组，整型数组
//int arr[10];
//char ch[10];
//
//字符数组是用来存放字符的，整型数组是用来存放整型的
//由此类推，指针数组就是用来存放指针的
//
// int* arr[5]
//数组名是arr，存放了5个元素，元素的类型是int*



//16.指针数组模拟二维数组

//代码展示：
int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 6,7,8,9,10 };
	int arr3[5] = { 11,12,13,14,15 };
	int* p[3] = { arr1,arr2,arr3 };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ",p[i][j]);
		}
		printf("\n");
	}
	return 0;
}


//p[i]是访问p数组的元素，p[i]找到的数组元素指向了整型一位数组
//parr[i][j]就是整型⼀维数组中的元素
//
//
//上述的代码模拟出⼆维数组的效果，
// 实际上并⾮完全是⼆维数组，因为每⼀⾏并⾮是连续的

